﻿//------------------------------------------------------------------------------------------------------
// The MIT License (MIT) Copyright (c) 2014 Marton Rusko
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
// associated documentation files (the "Software"), to deal in the Software without restriction, 
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial 
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//------------------------------------------------------------------------------------------------------
using System;
using System.IO;
using Ninject;
using Ninject.Parameters;
using RM.Banking.Unicredit.Statements.Exceptions;
using RM.Banking.Unicredit.Statements.Interfaces;

namespace RM.Banking.Unicredit.Statements
{
    /// <summary>
    /// Factory for Unicredit Statement Rows
    /// </summary>
    public class UnicreditStatementRecordFactory
    {
        #region Private fields

        /// <summary>
        /// Ninject kernel
        /// </summary>
        private static readonly StandardKernel Kernel;

        #endregion

        #region Constants

        /// <summary>
        /// Key for Ninject lookup
        /// </summary>
        private const string HeaderKey = "Header";

        #endregion

        #region Static constructor

        /// <summary>
        /// Static constructor: setup Ninject bindings
        /// </summary>
        static UnicreditStatementRecordFactory()
        {
            Kernel = new StandardKernel();

            Kernel.Bind<UnicreditStatementRecord>().To<UnicreditStatementHeaderRecord>()
                .WithMetadata(HeaderKey, UnicreditStatementRecordType.Header);
            Kernel.Bind<UnicreditStatementRecord>().To<UnicreditStatementDataRecord>()
                .WithMetadata(HeaderKey, UnicreditStatementRecordType.Data);
            Kernel.Bind<UnicreditStatementRecord>().To<UnicreditStatementWireTransferRecord>()
                .WithMetadata(HeaderKey, UnicreditStatementRecordType.WireTransfer);
        }

        #endregion

        #region Public methods

        /// <summary>
        /// Create a new Unicredit statement record from a StreamReader
        /// </summary>
        /// <param name="reader"></param>
        /// <returns>UnicreditStatementRecord derivate or null</returns>
        public static UnicreditStatementRecord Create(StreamReader reader)
        {
            if (reader == null) throw new ArgumentNullException("reader");

            string line = reader.ReadLine();
            if (line == null) //EOF
                return null;

            if (line.Length < 2)
                throw new InvalidUnicreditStatmentRowException("A sor rövidebb mint 2 karakter.");

            int recordTypeId;

            if (!int.TryParse(line.Substring(0, 2), out recordTypeId))
                return null;

            var result =
                Kernel.TryGet<UnicreditStatementRecord>(
                    metadata => metadata.Get<int>(HeaderKey) == recordTypeId,
                    new IParameter[] { new ConstructorArgument("line", line) });

            if (result is IHasExtenderRow && ((IHasExtenderRow)result).HasExtension())
            {
                var extenderRow = Create(reader);
                var extendableRow = result as ISetExtenderRow;
                if (extendableRow == null)
                    throw new Exception("Invalid class.");
                extendableRow.ExtenderRecord = extenderRow;
            }

            return result;
        }

        #endregion
    }
}